#include "fxcc/core/graph/opengl3/ImGuiGlfwApp.h"
#include "fxcc/imgui/Editor.h"

#include "fxcc/core/AssertManager.h"
#include "fxcc/core/graph/common/Geometry.h"
#include "fxcc/core/graph/common/ImageMipmap.h"
#include "fxcc/core/graph/opengl3/Texture2DJack.h"
#include "fxcc/core/graph/opengl3/Texture2DArrayJack.h"
#include "fxcc/core/graph/opengl3/Texture3DJack.h"
#include "fxcc/core/graph/opengl3/TextureCubeArrayJack.h"
#include "fxcc/core/graph/opengl3/MeshJack.h"
#include "fxcc/core/graph/opengl3/IndexBuffer.h"
#include "fxcc/core/graph/opengl3/RenderTargetJack.h"
#include "fxcc/core/graph/common/GlslShader.h"


using namespace fxcc::platform;
using namespace fxcc::graph::common;
using namespace fxcc::graph::opengl3;
using namespace fxcc::imgui::graph::opengl3;
using BaseApp = fxcc::imgui::graph::opengl3::GlfwApp;

#undef main

struct ShaderLoader
{
    static std::unordered_map<std::string, std::shared_ptr<fxcc::graph::opengl3::Effect3d>> m_Effects;

    bool Load(const std::string& fragCode, const std::string& key)
    {
        auto effect = std::make_shared<fxcc::graph::opengl3::Effect3d>(fragCode);
        m_Effects[key] = effect;
        return true;
    }
    bool LoadPath(const std::string& fragPath, const std::string& key)
    {
        return Load(fxcc::FileUtil::ReadFileToString(fragPath), key);
    } 
    std::shared_ptr<fxcc::graph::opengl3::Effect3d> GetEffect(const std::string& key)
    {
        auto it = m_Effects.find(key);
        if (it != m_Effects.end())
        {
            return it->second;
        }
        return 0;
    }
};

std::unordered_map<std::string, std::shared_ptr<fxcc::graph::opengl3::Effect3d>> ShaderLoader::m_Effects;

struct SimpleApp : public BaseApp
{
    glm::vec4 color;

    fxcc::graph::common::Camera camera;
    
    std::shared_ptr<fxcc::graph::opengl3::Effect3d> m_Effect;

    ShaderLoader m_ShaderLoader;

    fxcc::graph::common::MaterialView m_MaterialView;

    SimpleApp(const fxcc::platform::common::App::Desc& desc) : BaseApp(desc), color(1.0)
    {
    };

    bool Init() override
    {
        if (!BaseApp::Init())
        {
            return false;
        }
#ifdef _WIN32
        ImGuiIO& io = ImGui::GetIO();
        ImFont* font = io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/simhei.ttf", 25.0f, nullptr, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
        //ImFont* font = io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/msyh.ttc", 25.0f, nullptr, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
#endif

        if (!InitResources())
        {
            return false;
        }

        std::string vertCode = fxcc::graph::opengl3::Effect3d::GetVertAnimCode();

        std::string fragCode2 = R"(

out vec4 FragColor;

uniform sampler2D diffuseMap;
uniform sampler2DArray diffuse2DArray;
uniform sampler3D diffuse3D;
uniform samplerCube diffuseCube;
uniform samplerCubeArray diffuseCubeArray;

uniform int i1;
uniform ivec2 i2;
uniform ivec3 i3;
uniform ivec4 i4;

uniform float color;
uniform vec2 color2;
uniform vec3 color3;
uniform vec4 color4;

void main()
{
       float a=color.x+color2.x+color3.x+color4.x;
        int b=i1.x+i2.x+i3.x+i4.x;
        float c=texture(diffuseMap,TexCoord).r;
        float d=texture(diffuseCube,vec3(TexCoord,1.0f)).r;
        float e=texture(diffuse3D,vec3(TexCoord,1.0f)).r;
        float f=texture(diffuse2DArray,vec3(TexCoord,1.0f)).r;

        FragColor=vec4(vec3(a, b, c)*d* e* f, 1.0f);
        vec3 diffuseColor =texture(diffuseMap, TexCoord).rgb;
        FragColor.rgb=color3* diffuseColor;  
        FragColor.a=1.0f;
    
};
)";

        std::string shaderKey = "test_Shader";
        m_ShaderLoader.Load(fragCode2, "test_Shader");
        m_Effect = m_ShaderLoader.GetEffect(shaderKey);
        m_Effect->Influence(m_MaterialView);
        
        m_MaterialView.m_Textures.SetTexture2D("diffuseMap", fxcc::AssertManager::GetRelativeFile("Texture/stone.dds"));
        return true;
    };


    bool InitResources()
    {


        ImageMipmap::MipMapData image(1024, 1024, 4, 2);
        fxcc::graph::opengl3::RenderTargetJack::Desc desc(1, image);

        camera.SetPosition(glm::vec3(5.0f));
        camera.LookAt(glm::vec3(0.0f));

        return true;
    };

    fxcc::imgui::Editor editor;

    void OnEdit() override
    {
        ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());

        ImGui::Begin("Glsl Analysis");
        editor.EditInst<GlslShader>("glslShader", *m_Effect->m_ShaderLang);
        ImGui::End();

        ImGui::Begin("Material View");
        editor.EditInst<fxcc::graph::common::MaterialView>("m_MaterialView", m_MaterialView);
        ImGui::End();

        ImGui::Begin("RT");
        editor.AddFrameBuffer(m_RTJack->m_Textures[0]->GetTextureId());
        ImGui::End();
    }
    fxcc::graph::common::Transform transform;
    std::shared_ptr<fxcc::graph::opengl3::RenderTargetJack> m_RTJack;

    void OnDestroy() override
    {

        BaseApp::OnDestroy();
    }
    void OnFrameRender() override
    {
        glViewport(0, 0, m_Desc.m_Size.x, m_Desc.m_Size.y);
        glClearColor(color.x, color.y, color.z, color.w);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        m_RTJack->Begin();
        glClearColor(color.x, color.y, color.z, color.w);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        auto& buffers = fxcc::graph::opengl3::IBuffers::Inst();

        m_Effect->Begin();
        m_Effect->SetCamera(camera);
        fxcc::graph::common::Effect3d::ObjData objData;
        objData.Load(transform);
        m_Effect->SetObjData(objData);
        m_Effect->InstMeshJack(buffers.m_CubeMesh.get());
        m_Effect->UseMaterial(m_MaterialView);

        m_Effect->End();
        m_RTJack->End();

    };
    int fgIndex{ 0 };
    void OnRenderTextureArray(int fgIndex)
    {


    }
    void OnFramebuffersize(int w, int h) override
    {
        BaseApp::OnFramebuffersize(w, h);
        camera.SetAspect(m_Desc.Aspect());
        fxcc::graph::opengl3::RenderTargetJack::Desc desc(1, { w, h, 3, 0 });
        m_RTJack = std::make_shared<fxcc::graph::opengl3::RenderTargetJack>(desc);


    }
    void OnUpdate() override
    {
        BaseApp::OnUpdate();

        float ctTime = m_GlfwlTimer.m_CurrentTime;
        float deltaTime = m_GlfwlTimer.m_DeltaTime;


    }
};

int main()
{
    ztclog::pushFunction([](const ztclog::Line& line)
        {
            if (line.m_Type != ztclog::Line::Type::_line_debug_)
            {
                std::cout << line.m_Text << std::endl;
            } });

            using _App = SimpleApp;
            using _Desc = fxcc::platform::common::App::Desc;

            _Desc desc;
            desc.m_Pos = glm::ivec2(100, 100);
            desc.m_Size = glm::ivec2(900, 600);
            desc.m_ScaleFactor = 1.0f;

            desc.m_Title = "glsl editor";
            std::shared_ptr<_App> _app = std::make_shared<_App>(desc);
            return _app->Run();
};
